package com.mkirl;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;

import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.location.Location;
import android.location.LocationManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.os.Handler;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;

public class MKIRL extends MapActivity {

	List<Overlay> mapOverlays;
	Drawable defaultOverlayDrawable;
	LocationManager locationManager;
	public Player thisPlayer;
	public Game thisGame;
	public ServerCommunicator srvCommunicator;
	MapView mapView;
	boolean inGame;
	GamesItemizedOverlay gamesItemizedOverlay;
	PlayersItemizedOverlay playersItemizedOverlay;
	GameObjectsItemizedOverlay gameObjsItemizedOverlay;
	AdvancedLocationOverlay playerLocationOverlay;
	MapController mapController;
	CountDownTimer updateTimer;
	final long MAX_GAME_LENGTH = 10000000; //in millis
	final long UPDATE_SERVER_INTERVAL = 6000; //in millis
	final long ECHO_COOLDOWN = 60000;
	TextView tickerTextView;
	TextView stateTextView;
	public final String WHERE_IS_ITEM_CMD = "whereIsItem";
	public final String AT_ITEM_CMD = "atItem";
	public final String DRAWING_CORNER_CMD = "drawingCorner";
	public final String SET_TREASURE_CMD = "setTreasure";
	public final String START_NEW_GAME_CMD = "startNewGame";
	public final String ECHO_CMD  = "echo";
	public GameObject ourTreasure;
	public final int TICKER_TEXT_SIZE = 14;
	boolean canEcho;
	MKIRL mkirl;
	Button digHereBtn;
	Button setTreasureBtn;
	int ascore, bscore, treasurestoplace;
	int AScore, BScore, treasuresToPlace;
	Handler updateHandler;
	public int WINNING_SCORE = 5;
	
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        mkirl = this;
        srvCommunicator = new ServerCommunicator(this);
        inGame = false;
        canEcho = false;
        ourTreasure = new GameObject(34.500000,-118.210000, "Team A", "Team A");
        updateHandler = new Handler();
        
        String startDialogTitle = getString(R.string.startDialogTitle);
        String startDialogMessage = getString(R.string.startDialogMessage);
        AlertDialog.Builder dialog = new AlertDialog.Builder(mkirl);
	    dialog.setTitle(startDialogTitle);
	    dialog.setMessage(startDialogMessage);
	    
	    dialog.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
		    public void onClick(DialogInterface dialog, int whichButton) {
		    	//let user pass
		    }
		    });
		dialog.show();
        
        stateTextView = (TextView) findViewById(R.id.stateTextView);
        stateTextView.setTextColor(Color.WHITE);
        //initialize tickerTextView and make it pull up server command debug sender when clicked
        tickerTextView = (TextView) findViewById(R.id.tickerTextView);
        tickerTextView.setClickable(true);
        tickerTextView.setTextSize(TICKER_TEXT_SIZE);
        tickerTextView.setOnClickListener(new OnClickListener() {
        	@Override
        	public void onClick(View v) {
        		//build popup
        		AlertDialog.Builder dialog = new AlertDialog.Builder(mkirl);
        	    dialog.setTitle("Debug Server Commands Prompt");
        	    dialog.setMessage("\nEnter Command:");
        	    
        	    // Set an EditText view to get user input 
        	    final EditText input = new EditText(mkirl);
        	    dialog.setView(input);//add EditText to popup
        	    
        	    dialog.setPositiveButton("Send", new DialogInterface.OnClickListener() {
        		    public void onClick(DialogInterface dialog, int whichButton) {
        		    	String value = input.getEditableText().toString();
        		    	new SendDebugCommandTask(value).execute();
        		    }
        		    });
        	    dialog.setNegativeButton("Back", new DialogInterface.OnClickListener() {
        		      public void onClick(DialogInterface dialog, int whichButton) {
        		        // Canceled.
        		      }
        		    });
        		dialog.show();
        	}
        });
        
        initializeMap();
        initializePlayer();
    }
    
    //just a simplified method for creating a SendCommandTask
    public void sendCommand(String command) {
    	new SendCommandTask(thisPlayer, command).execute();
    }
    
    public void initializeMap() {
    	mapView = (MapView) findViewById(R.id.mapview);
        mapView.setBuiltInZoomControls(true);
        mapController = mapView.getController();
        //allow drawables to be placed on the map
        mapOverlays = mapView.getOverlays();
        defaultOverlayDrawable = this.getResources().getDrawable(R.drawable.maps_marker);
        gamesItemizedOverlay = new GamesItemizedOverlay(defaultOverlayDrawable, this);
        gameObjsItemizedOverlay = new GameObjectsItemizedOverlay(defaultOverlayDrawable, this);
        playersItemizedOverlay = new PlayersItemizedOverlay(defaultOverlayDrawable, this);
    }
    
    public void initializePlayer() {
        playerLocationOverlay = new AdvancedLocationOverlay(this, mapView);
        thisPlayer = new Player(playerLocationOverlay);
        playerLocationOverlay.enableMyLocation();
        playerLocationOverlay.enableCompass();
        mapView.getOverlays().add(playerLocationOverlay);
        tickerTextView.setText("Loading Games");
        tickerTextView.setTextColor(Color.GRAY);
       	final ShowLocalGamesTask showLocalGamesTask = new ShowLocalGamesTask();
        playerLocationOverlay.runOnFirstFix(new Runnable() {
        	
            public void run() {
            	mapController.animateTo(playerLocationOverlay.getMyLocation());
            	mapController.setZoom(18);
            	showLocalGamesTask.execute(playerLocationOverlay.getMyLocation());
            }
        }
        );
        
    }
    
    public void initializeButtons() {
    	//SET TREASURE BUTTON
    	setTreasureBtn = (Button) findViewById(R.id.setTreasureBtn);
    	setTreasureBtn.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                sendCommand("setTreasure");
            }        
        });  //end onClickListener
    	
    	//DIG HERE BUTTON
    	digHereBtn = (Button) findViewById(R.id.digHereBtn);
    	digHereBtn.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                sendCommand("atItem");
            }        
        });  //end onClickListener
    	
    	setTreasureBtn.setVisibility(View.VISIBLE);
    	digHereBtn.setVisibility(View.VISIBLE);
    }
    
	public void joinGame() {
		AlertDialog.Builder dialog = new AlertDialog.Builder(mkirl);
	    dialog.setTitle("Team Selection");
	    dialog.setMessage("\nChoose Your Team:");

	    dialog.setPositiveButton("Webfest A", new DialogInterface.OnClickListener() {
	    public void onClick(DialogInterface dialog, int whichButton) {
	    	thisPlayer.setTeam("Webfest A");
			tickerTextView.setText("Joined game " + thisPlayer.getGameID() + " on team "+thisPlayer.getTeam());
			tickerTextView.setTextColor(Color.GRAY);
	      }
	    });
	    
	    dialog.setNegativeButton("Webfest B", new DialogInterface.OnClickListener() {
	      public void onClick(DialogInterface dialog, int whichButton) {
		    	thisPlayer.setTeam("Webfest B");
				tickerTextView.setText("You have joined the game " + thisPlayer.getGameID() + " on "+thisPlayer.getTeam());
				tickerTextView.setTextColor(Color.GRAY);
	      }
	    });
	    dialog.show();
		

		srvCommunicator.postPlayerToServer(thisPlayer);
		updateTimer = new CountDownTimer( MAX_GAME_LENGTH, UPDATE_SERVER_INTERVAL) {

            public void onTick(long millisUntilFinished) {
            	if (inGame){
                	srvCommunicator.postPlayerToServer(thisPlayer);
            	}
            }

            public void onFinish() {
            	inGame = false;
            }
         }.start();
         
         //all this should only happen if the server doesn't reject the first postPlayer (eventually)
         //remove the games, they are no longer needed
         if (inGame) {
         mapView.getOverlays().remove(gamesItemizedOverlay);
         mapView.invalidate();
         initializeGameInstance();
         }
	}
	
	@Override
	protected boolean isRouteDisplayed() {
		// TODO Auto-generated method stub
		return false;
	}

	public void echo() {
		if (canEcho && inGame) {
			
			/*
			float[] results = new float[1];
			//format treasure location so that decimals are not truncated
			double treasureLat = ourTreasure.getLatitude();
			double treasureLng = ourTreasure.getLongitude();
			
			//treasureLat /= 1000000;
			//treasureLng /= 1000000;
			
			Location.distanceBetween(thisPlayer.getLocation().getLatitude(), thisPlayer.getLocation().getLongitude(), treasureLat, treasureLng, results);
			tickerTextView.setText("You are "+results[0]+" meters from the treasure");
			//tickerTextView.setText("treasure at: "+treasureLat+ " " + treasureLng + " player at "+thisPlayer.getLocation().getLatitude()+thisPlayer.getLocation().getLongitude());
			tickerTextView.setTextColor(Color.WHITE);
			canEcho = false;
			*/
			
			//create a countDownTimer to allow the Player to echo again after 60 seconds
			sendCommand("echo");
			new CountDownTimer(ECHO_COOLDOWN, ECHO_COOLDOWN) {

				@Override
				public void onFinish() {
					canEcho = true;
				}

				@Override
				public void onTick(long millisUntilFinished) {
					// TODO Auto-generated method stub
				}
			}.start();
		}
		else if (!canEcho) {
			tickerTextView.setText("You can only echo once every 60 seconds");
			tickerTextView.setTextColor(Color.RED);
		}
		else {
			tickerTextView.setText("You can't echo while not in a game");
			tickerTextView.setTextColor(Color.RED);
		}
	}
	
	//called from joinGame()
	public void initializeGameInstance() {
		//retrieve gameState from Server (eventually)
		thisGame = new Game(thisPlayer.getGameID(), new GeoPoint(34024879, -118288451));
		sendCommand(WHERE_IS_ITEM_CMD); //call Where is Item and get it to change thisGame's item location (eventually gameState is retrievable)
		canEcho = true;
        initializeButtons();
	}
	
	@Override
	public void onConfigurationChanged(Configuration newConfig) {
	    super.onConfigurationChanged(newConfig);
	    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
	}
	
	/* JUST AN IDEA
	updateItemLoc() {
		
	}
	*/
	
//must instantiate with current player and command string and then execute
public class SendCommandTask extends AsyncTask<Void, Void, String> {
	
	Player player;
	String command;
	public SendCommandTask(Player player, String command) {
		this.player = player;
		this.command = command;
	}
	
	@Override
	protected String doInBackground(Void... unused) {
		HttpClient httpclient = new DefaultHttpClient();
	    HttpPost httppost = new HttpPost("http://10.mkirlgame.appspot.com/update?gameID="+player.getGameID());
	    String responseAsStr = "";
	    
	    try{
	    	List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
	    	nameValuePairs.add(new BasicNameValuePair("command", command));
	    	nameValuePairs.add(new BasicNameValuePair("playerID", player.getPlayerID()));
	        nameValuePairs.add(new BasicNameValuePair("latitude", "" + player.getLatitude()));
	        nameValuePairs.add(new BasicNameValuePair("longitude", "" + player.getLongitude()));
	    	nameValuePairs.add(new BasicNameValuePair("team", player.getTeam()));
	        nameValuePairs.add(new BasicNameValuePair("userClass", player.getUserClass()));
	    	nameValuePairs.add(new BasicNameValuePair("heading", ""+player.getHeading()));
	        nameValuePairs.add(new BasicNameValuePair("gpsAccuracy", ""+player.getGPSAccuracy()));
	    	httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
	    	// Execute HTTP Post Request
	    	HttpResponse response = httpclient.execute(httppost);            
	    	
	    	if(response!=null){
	    		StringBuffer out = new StringBuffer();
	    	    byte[] b = new byte[4096];
	    	    InputStream is = response.getEntity().getContent();
	    	    for (int n; (n = is.read(b)) != -1;) {
	    	        out.append(new String(b, 0, n));
	    	    }
	    	    responseAsStr = out.toString();
	    	}
	    	
	    }
	    catch (ClientProtocolException e) {
	        // TODO Auto-generated catch block
	    } 
	    catch (IOException e) {
	        // TODO Auto-generated catch block
	    }
	    return responseAsStr;
	}
	
	@Override
	protected void onPostExecute(String response) {
		if(command.equals(WHERE_IS_ITEM_CMD)) {
			double latitude = 0;
			double longitude = 0;
			try{
				String[] cords = response.split(" ");
				latitude = Double.parseDouble(cords[0]);
				longitude = Double.parseDouble(cords[1]);
				//tickerTextView.setText(cords[0] +" from whereIsItem "+cords[1]);
			}
			catch(NumberFormatException e) {
				e.printStackTrace();
			}
			
			//WHEREISITEM should add item to thisGame
			ourTreasure = new GameObject(latitude, longitude, "Treasure", thisPlayer.getTeam());
			
			//DEBUG PURPOSES ONLY, doesn't need to be displayed
			//thisGame.getGameObjs().add(ourTreasure);
			
			/*
			CREATE ITEM
			for(GameObject gameObj : thisGame.getGameObjs()) {
				REPLACE IF ANOTHER EXISTS
			}
			*/
			
			/*	CURRENTLY NO GAME OBJECTS TO BE DRAWN, THROWS NULL POINTER IF GAMEOBJS IS EMPTY
			for(GameObject gameObj : thisGame.getGameObjs()) {
				gameObjsItemizedOverlay.addOverlay(gameObj.getOverlay());
			}
			mapOverlays.add(gameObjsItemizedOverlay);
			*/
		}
		else if (command.equals(AT_ITEM_CMD)) {
			if(response.equals("1")) {
				tickerTextView.setText("You located a treasure!");
				tickerTextView.setTextColor(Color.GRAY);
			}
			else {
				tickerTextView.setText("No treasure here");
				tickerTextView.setTextColor(Color.GRAY);
			}
		}
		else if (command.equals(DRAWING_CORNER_CMD)) {
			//do nothing
		}
		else if (command.equals(SET_TREASURE_CMD)) {
			if(response.equals("1")) {
				tickerTextView.setText("Treasure placed");
				tickerTextView.setTextColor(Color.GRAY);
			}
			else {
				tickerTextView.setText("Unable to place treasure at this time");
				tickerTextView.setTextColor(Color.GRAY);
			}
		}
		else if (command.equals(START_NEW_GAME_CMD)) {
			
		}
		else if (command.equals(ECHO_CMD)) {
			if (response.equalsIgnoreCase("null")) {
				tickerTextView.setText("Other team hasn't buried your treasure yet");
				tickerTextView.setTextColor(Color.GRAY);
			}
			else {
				tickerTextView.setText("You are "+response+" meters from the treasure");
				tickerTextView.setTextColor(Color.GRAY);
			}
		}
			
	}


	@Override
	protected void onPreExecute() {
		if (command.equals(ECHO_CMD)){
			tickerTextView.setText("Echo-Locating...");
			tickerTextView.setTextColor(Color.GRAY);
		}
		else if (command.equals(AT_ITEM_CMD)) {
			tickerTextView.setText("Digging for treasure...");
			tickerTextView.setTextColor(Color.GRAY);
		}
		else if (command.equals(SET_TREASURE_CMD)) {
			tickerTextView.setText("Attempting to place treasure...");
			tickerTextView.setTextColor(Color.GRAY);
		}
	}


	@Override
	protected void onProgressUpdate(Void... values) {
      // Things to be done while execution of long running operation is in progress. For example updating ProgessDialog
	 }
	
}

//must instantiate with current player and command string and then execute
public class SendDebugCommandTask extends AsyncTask<Void, Void, String> {
	
	String command;
	public SendDebugCommandTask(String command) {
		this.command = command;
	}
	
	@Override
	protected String doInBackground(Void... unused) {
		HttpClient httpclient = new DefaultHttpClient();
	    HttpPost httppost = new HttpPost("http://10.mkirlgame.appspot.com/update?gameID=Webfest_Game");
	    String responseAsStr = "";
	    
	    try{
	    	List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
	    	nameValuePairs.add(new BasicNameValuePair("command", command));
	    	nameValuePairs.add(new BasicNameValuePair("playerID", "su"));
	        nameValuePairs.add(new BasicNameValuePair("latitude", "34.023530"));
	        nameValuePairs.add(new BasicNameValuePair("longitude", "-118.286432"));
	    	nameValuePairs.add(new BasicNameValuePair("team", "Webfest A"));
	        nameValuePairs.add(new BasicNameValuePair("userClass", "overlord"));
	    	nameValuePairs.add(new BasicNameValuePair("heading", "0.0"));
	        nameValuePairs.add(new BasicNameValuePair("gpsAccuracy","5.0"));
	    	httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
	    	// Execute HTTP Post Request
	    	HttpResponse response = httpclient.execute(httppost);            
	    	
	    	if(response!=null){
	    		StringBuffer out = new StringBuffer();
	    	    byte[] b = new byte[4096];
	    	    InputStream is = response.getEntity().getContent();
	    	    for (int n; (n = is.read(b)) != -1;) {
	    	        out.append(new String(b, 0, n));
	    	    }
	    	    responseAsStr = out.toString();
	    	}
	    	
	    }
	    catch (ClientProtocolException e) {
	        // TODO Auto-generated catch block
	    } 
	    catch (IOException e) {
	        // TODO Auto-generated catch block
	    }
	    return responseAsStr;
	}
	
	@Override
	protected void onPostExecute(String response) {
		tickerTextView.setText(response);
	}


	@Override
	protected void onPreExecute() {
	// Things to be done before execution of long running operation. For example showing ProgessDialog
	}


	@Override
	protected void onProgressUpdate(Void... values) {
      // Things to be done while execution of long running operation is in progress. For example updating ProgessDialog
	 }
	
}

//must instantiate and then execute with current location as GeoPoint
public class ShowLocalGamesTask extends AsyncTask<GeoPoint, Void, ArrayList<Game>> {

		String localGamesStrNET;
		
		@Override
		protected ArrayList<Game> doInBackground(GeoPoint... p) {
			ArrayList<Game> localGames = new ArrayList<Game>();
			String localGamesStr = "";
			
			HttpClient httpclient = new DefaultHttpClient();
		    HttpPost httppost = new HttpPost("http://10.mkirlgame.appspot.com/games");

		    
		    double playerLatitude = p[0].getLatitudeE6();
			double playerLongitude = p[0].getLongitudeE6();
			//turn lat and lng into microdegrees to create a GeoPoint
			playerLatitude *= 1000000;
			playerLongitude *= 1000000;
		    
		    try{
		    	//List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
		        //nameValuePairs.add(new BasicNameValuePair("latitude", "" + playerLatitude));
		        //nameValuePairs.add(new BasicNameValuePair("longitude", "" + playerLongitude));

		    	//httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
		    	// Execute HTTP Post Request
		    	HttpResponse response = httpclient.execute(httppost);            
		    	
		    	if(response!=null){
		    		StringBuffer out = new StringBuffer();
		    	    byte[] b = new byte[4096];
		    	    InputStream is = response.getEntity().getContent();
		    	    for (int n; (n = is.read(b)) != -1;) {
		    	        out.append(new String(b, 0, n));
		    	    }
		    	    localGamesStrNET = out.toString();
		    	    //localGamesStr = localGamesStrNET;
		    	}
		    }
			catch (ClientProtocolException e) {
		        // TODO Auto-generated catch block
		    } 
			catch (IOException e) {
		        // TODO Auto-generated catch block
		    }

			try{
				//Game strings are currently hardcoded
				localGamesStr = "Webfest_Game 34.023715976 -118.28405785";
				
				//Separate each game instance into a separate string within an array of strings
				String[] localGamesStrArr = localGamesStr.split(";");
				
				
				
				//build list of Games from string array
				for (int i = 0; i < localGamesStrArr.length; i++) {
					String[] gameComponents = localGamesStrArr[i].split(" ");
					if (gameComponents.length == 3){
						String gameID = gameComponents[0];
						double gameLatitude = Double.parseDouble(gameComponents[1]);
						double gameLongitude = Double.parseDouble(gameComponents[2]);
						//turn lat and lng into microdegrees to create a GeoPoint
						gameLatitude *= 1000000;
						gameLongitude *= 1000000;
						//create a new game having the given gameID and having a GeoPoint at the given latitude and longitude
						localGames.add(new Game(gameID, new GeoPoint((int)gameLatitude, (int)gameLongitude)));
					}
					
					else
						throw new Exception("server returned unknown list type with more or less than 3 components");	
				}
				
			}
			catch (Exception e) {
				tickerTextView.setText(e.getMessage());
				tickerTextView.setTextColor(Color.RED);
			}
			
			return localGames;
		}


		@Override
		protected void onPostExecute(ArrayList<Game> localGames) {
			//add all games overlay's to the ItemizedList of game overlays
			for (Game game : localGames) {
	    		gamesItemizedOverlay.addOverlay(game.getOverlay());
	    	}
	    	//add the itemizedList of game overlays to the map's list of overlays
	    	mapOverlays.add(gamesItemizedOverlay);
	    	tickerTextView.setText("Local games have been loaded");
	    	tickerTextView.setTextColor(Color.GRAY);
	    	inGame = true;
		}


		@Override
		protected void onPreExecute() {
		// Things to be done before execution of long running operation. For example showing ProgessDialog
		}


		@Override
		protected void onProgressUpdate(Void... values) {
	      // Things to be done while execution of long running operation is in progress. For example updating ProgessDialog
		 }
	}//end inner class import 
	
	public void updateGameState(int a, int b, int treasures) {
		AScore = a;
		BScore = b;
		treasuresToPlace = treasures;
		
		if (a >= WINNING_SCORE || b >= WINNING_SCORE) {
			AlertDialog.Builder dialog = new AlertDialog.Builder(mkirl);
		    dialog.setTitle("GAME OVER");
		    if( a >= WINNING_SCORE)
		    	dialog.setMessage("Team Webfest A Won!");
		    else if (b >= WINNING_SCORE)
		    	dialog.setMessage("Team Webfest B Won!");
		    
		    dialog.setPositiveButton("New Game", new DialogInterface.OnClickListener() {
			    public void onClick(DialogInterface dialog, int whichButton) {
			    	sendCommand(START_NEW_GAME_CMD);
			    }
			    });
			dialog.show();
		}

		stateTextView.setText("Webfest A: "+a+" Webfest B: "+b+" Treasures to Place: "+treasures);
		stateTextView.invalidate();
	}
	
public Runnable updateRunnable = new Runnable() {
	public void run() {
		updateGameState(ascore, bscore, treasurestoplace);
	}
	
};

}//end outter MKIRL class